/*
 * Copyright 2002-2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.transaction;

import java.sql.Connection;

import org.springframework.lang.Nullable;

/**
 * Interface that defines Spring-compliant transaction properties.
 * Based on the propagation behavior definitions analogous to EJB CMT attributes.
 *
 * <p>Note that isolation level and timeout settings will not get applied unless
 * an actual new transaction gets started. As only {@link #PROPAGATION_REQUIRED},
 * {@link #PROPAGATION_REQUIRES_NEW} and {@link #PROPAGATION_NESTED} can cause
 * that, it usually doesn't make sense to specify those settings in other cases.
 * Furthermore, be aware that not all transaction managers will support those
 * advanced features and thus might throw corresponding exceptions when given
 * non-default values.
 *
 * <p>The {@link #isReadOnly() read-only flag} applies to any transaction context,
 * whether backed by an actual resource transaction or operating non-transactionally
 * at the resource level. In the latter case, the flag will only apply to managed
 * resources within the application, such as a Hibernate {@code Session}.
 *
 * @author Juergen Hoeller
 * @since 08.05.2003
 * @see PlatformTransactionManager#getTransaction(TransactionDefinition)
 * @see org.springframework.transaction.support.DefaultTransactionDefinition
 * @see org.springframework.transaction.interceptor.TransactionAttribute
 *
 *
 * 事务属性包括5大方面
 * 1） 传播行为
 * 2） 隔离规则
 * 3） 是否只读
 * 4） 回滚规则
 * 5） 事务超时
 *
 * 没有事务 新建 非事务 抛出异常
 * 有事务  当前  挂起新建  挂起非事务， 抛出异常，嵌套
 *
 * 新建+当前 PROPAGATION_REQUIRED（常用）
 * 新建+ 挂起新建 PROPAGATION_REQUIRES_NEW（常用）
 * 新建+嵌套  PROPAGATION_NESTED
 *
 * 抛出异常+当前 PROPAGATION_MANDATORY
 * 非事务+当前 PROPAGATION_SUPPORTS
 *
 * 非事务+挂起非事务  PROPAGATION_NOT_SUPPORTED
 * 非事务+抛出异常   PROPAGATION_NEVER
 *
 *
 *
 * 外层是2个状态
 * 新建（2个）、抛出异常1（个）
 *
 *
 * 内层是5个状态
 *
 */
public interface TransactionDefinition {

	// 7种事务传播属性
	/**
	 * 如果当前没有事务，新建一个事务，
	 * 如果已经存在事务，使用这个事务。这是最常见的选择。
	 */
	int PROPAGATION_REQUIRED = 0;
	/**
	 * 如果当前没有事务，以非事务方式执行
	 * 如果已经存在事务，使用这个事务
	 */
	int PROPAGATION_SUPPORTS = 1;

	/**
	 * 如果当前没有事务，抛出异常
	 * 如果已经存在事务，使用这个事务。
	 */
	int PROPAGATION_MANDATORY = 2;

	/**
	 * 如果当前没有事务，新建事务
	 * 如果存在事务，把当前事务挂起，新建事务  这个也是使用较多的  相当于另起炉灶
 	 */
	int PROPAGATION_REQUIRES_NEW = 3;

	/**
	 * 如果当前没有事务，以非事务方式执行操作
	 * 如果当前存在事务，就把当前事务挂起，以非事务运行。
	 */
	int PROPAGATION_NOT_SUPPORTED = 4;

	/**
	 * 如果当前没有事务，以非事务方式执行
	 * 如果当前存在事务，则抛出异常。
	 */
	int PROPAGATION_NEVER = 5;

	/**
	 * 如果当前没有事务，新建一个事务
	 * 如果当前存在事务，则在嵌套事务(它是一个子事务，但他仍还是外部事务的一部分，外部事务提交了它才提交。。。注意和REQUIRES_NEW的区别~~~)内执行。
	 *
	 */
	int PROPAGATION_NESTED = 6;


	/**
	 *  4种：隔离级别
	 * 	MySQL默认采用ISOLATION_REPEATABLE_READ，Oracle采用READ__COMMITTED级别
 	 */
	int ISOLATION_DEFAULT = -1;

	/**
	 * 读未提交
	 */
	int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;

	/**
	 * 读已提交
	 */
	int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;

	/**
	 * 可重复读
	 */
	int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;

	/**
	 * 序列化
	 */
	int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;


	/**
	 * 超时时间 -1表示不超时
	 * 如果超过时间限制但事务还没完成，则自动回滚事务
	 */
	int TIMEOUT_DEFAULT = -1;


	/**
	 * Return the propagation behavior.
	 * <p>Must return one of the {@code PROPAGATION_XXX} constants
	 * defined on {@link TransactionDefinition this interface}.
	 * @return the propagation behavior
	 * @see #PROPAGATION_REQUIRED
	 * @see org.springframework.transaction.support.TransactionSynchronizationManager#isActualTransactionActive()
	 */
	int getPropagationBehavior();

	/**
	 * Return the isolation level.
	 * <p>Must return one of the {@code ISOLATION_XXX} constants defined on
	 * {@link TransactionDefinition this interface}. Those constants are designed
	 * to match the values of the same constants on {@link java.sql.Connection}.
	 * <p>Exclusively designed for use with {@link #PROPAGATION_REQUIRED} or
	 * {@link #PROPAGATION_REQUIRES_NEW} since it only applies to newly started
	 * transactions. Consider switching the "validateExistingTransactions" flag to
	 * "true" on your transaction manager if you'd like isolation level declarations
	 * to get rejected when participating in an existing transaction with a different
	 * isolation level.
	 * <p>Note that a transaction manager that does not support custom isolation levels
	 * will throw an exception when given any other level than {@link #ISOLATION_DEFAULT}.
	 * @return the isolation level
	 * @see #ISOLATION_DEFAULT
	 * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setValidateExistingTransaction
	 */
	int getIsolationLevel();

	/**
	 * Return the transaction timeout.
	 * <p>Must return a number of seconds, or {@link #TIMEOUT_DEFAULT}.
	 * <p>Exclusively designed for use with {@link #PROPAGATION_REQUIRED} or
	 * {@link #PROPAGATION_REQUIRES_NEW} since it only applies to newly started
	 * transactions.
	 * <p>Note that a transaction manager that does not support timeouts will throw
	 * an exception when given any other timeout than {@link #TIMEOUT_DEFAULT}.
	 * @return the transaction timeout
	 *
	 *
	 *默认的超时时间 -1表示不超时（单位是秒）
	 * 如果超过该时间限制但事务还没有完成，则自动回滚事务
	 */
	int getTimeout();

	/**
	 * Return whether to optimize as a read-only transaction.
	 * <p>The read-only flag applies to any transaction context, whether backed
	 * by an actual resource transaction ({@link #PROPAGATION_REQUIRED}/
	 * {@link #PROPAGATION_REQUIRES_NEW}) or operating non-transactionally at
	 * the resource level ({@link #PROPAGATION_SUPPORTS}). In the latter case,
	 * the flag will only apply to managed resources within the application,
	 * such as a Hibernate {@code Session}.
	 * <p>This just serves as a hint for the actual transaction subsystem;
	 * it will <i>not necessarily</i> cause failure of write access attempts.
	 * A transaction manager which cannot interpret the read-only hint will
	 * <i>not</i> throw an exception when asked for a read-only transaction.
	 * @return {@code true} if the transaction is to be optimized as read-only
	 *
	 * @see org.springframework.transaction.support.TransactionSynchronization#beforeCommit(boolean)
	 * @see org.springframework.transaction.support.TransactionSynchronizationManager#isCurrentTransactionReadOnly()
	 * 事务是否只读(事务管理器能够根据这个返回值进行优化，确保事务是只读的)
	 */
	boolean isReadOnly();

	/**
	 * Return the name of this transaction. Can be {@code null}.
	 * <p>This will be used as the transaction name to be shown in a
	 * transaction monitor, if applicable (for example, WebLogic's).
	 * <p>In case of Spring's declarative transactions, the exposed name will be
	 * the {@code fully-qualified class name + "." + method name} (by default).
	 * @return the name of this transaction
	 * @see org.springframework.transaction.interceptor.TransactionAspectSupport
	 * @see org.springframework.transaction.support.TransactionSynchronizationManager#getCurrentTransactionName()
	 */
	@Nullable
	String getName();

}
